﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using SqlSugar;
using Sunny.UI.Win32;
using 数据迁移工具.Factory;

namespace 数据迁移工具.Common.DbContext
{
    public class MySqlDbContext : SugarDbContext
    {
        private CancellationToken ct = new CancellationToken();

        public MySqlDbContext(ConnectionConfig config) : base(config)
        {
        }

        public override List<TableInfo> GetTableInfos(string dbName)
        {
            string sql = $"select TABLE_SCHEMA as DbName,TABLE_NAME as TbName,TABLE_TYPE as TbType,TABLE_ROWS as TbRows from information_schema.`TABLES` where TABLE_SCHEMA = '{dbName}'";
            return DB.Ado.SqlQuery<TableInfo>(sql);
        }

        #region 视图转换逻辑
        public override void ViewConvert(string srcMode, DbType dbType,string targetId, string dstDbName)
        {
            List<ViewDefinition> definitions = GetViewDefinitions(srcMode);
            switch (dbType)
            {
                case DbType.MySql:
                    break;
                case DbType.SqlServer:
                    break;
                case DbType.Sqlite:
                    break;
                case DbType.Oracle:
                    break;
                case DbType.PostgreSQL:
                    break;
                case DbType.Dm:
                    MySqlToDmView(definitions, targetId, dstDbName);
                    break;
                default:
                    break;
            }
        }
        
        public void MySqlToDmView(List<ViewDefinition> definitions, string targetId, string dstDbName)
        {
            List<ViewDefinition> errorViews = new List<ViewDefinition>();

            ConnectionConfig? connConfig = ConnectionConfigs.FirstOrDefault(c => c.ConfigId == targetId);
            if (connConfig == null)
                throw new Exception("指定的数据源Id未找到");
            SugarDbContext dstContext = DbFactory.CreateDbContext(DbType.Dm, connConfig);
            string viewTemplate = "CREATE OR REPLACE VIEW `{0}`.`{1}` AS {2}";

            // 执行两次的目的，防止存在视图之间相互依赖时，第一次执行时因依赖视图未被创建而导致的视图创建失败问题
            int count = 1;

            while (count <= 2)
            {
                foreach (var definition in definitions)
                {
                    if (count == 1)
                    {
                        string createViewStr = string.Format(viewTemplate, dstDbName, definition.VIEW_NAME, definition.VIEW_DEFINITION);
                        definition.VIEW_DEFINITION = createViewStr.Replace("“", "").Replace("\"", "`");
                    }
                    bool res = CreateView(dstContext, definition.VIEW_NAME, definition.VIEW_DEFINITION);
                    // 如果第一次执行没有任何失败就不再执行第二次
                    if (!res)
                    {
                        errorViews.Add(definition);
                    }
                    else
                    {
                        ConsoleLog.Success("RichText", $"视图 {definition.VIEW_NAME} 创建成功.");
                    }
                }
                if (errorViews.Count == 0) break;
                definitions.Clear();
                definitions.AddRange(errorViews);
                errorViews.Clear();
                count++;
            }

            foreach (var errorView in definitions)
            {
                ConsoleLog.Error("RichText", $"视图 {errorView.VIEW_NAME} 创建失败: {errorView.VIEW_DEFINITION}\n");
                string path = Directory.GetCurrentDirectory() + "\\ViewLog";
                if (!Directory.Exists(path))
                    Directory.CreateDirectory(path);
                File.WriteAllText($"{path}\\{errorView.VIEW_NAME}.log", errorView.VIEW_DEFINITION);
            }
        }

        #endregion

        #region 迁移逻辑

        public override void DbMigrate(DbType targetType,string targetId, string dbName, string namesp = "Default.Models")
        {
            switch (targetType)
            {
                case DbType.MySql:
                    MySqlToMySqlMigrate(ConfigId, targetId, dbName, namesp);
                    break;
                case DbType.SqlServer:
                    break;
                case DbType.Sqlite:
                    break;
                case DbType.Oracle:
                    MySqlToOracleMigrate(ConfigId,targetId, dbName, namesp);
                    break;
                case DbType.PostgreSQL:
                    break;
                case DbType.Dm:
                    break;
                default:
                    break;
            }
        }

        /// <summary>
        /// MySql 数据源向 MySql 数据源迁移
        /// </summary>
        /// <param name="sourceId"></param>
        /// <param name="targetId"></param>
        /// <param name="dbName"></param>
        /// <param name="namesp"></param>
        private void MySqlToMySqlMigrate(string sourceId, string targetId, string dbName, string namesp)
        {
            if (DynamicHelper.ModelAssembly == null)
            {
                ConsoleLog.Error("RichText", "实体类程序集未初始化");
                return;
            }

            if (ConnectionConfigs == null || ConnectionConfigs.Count == 0)
                throw new Exception("请检查是否初始化 SugarDbContext.ConnectionConfigs");

            ConnectionConfig? connConfig = ConnectionConfigs.FirstOrDefault(c => c.ConfigId == sourceId);
            if (connConfig == null)
                throw new Exception("指定的数据源Id未找到");
            SqlSugarClient client = new SqlSugarClient(connConfig);
            string sql1 = $"select TABLE_NAME from information_schema.`TABLES` WHERE TABLE_SCHEMA = '{dbName}' and TABLE_TYPE = 'BASE TABLE'";
            List<string> tables = client.Ado.SqlQuery<string>(sql1);
            // tables = sugarDbContext.DB.Queryable("ALL_ALL_TABLES", "tb").Where("tb.OWNER = 'CIMS2023'").Select<string>("TABLE_NAME").ToList();
            tableRowMap.Clear();
            foreach (var table in tables)
            {
                string sql = $"select count(*) from {table}";
                int count = client.Ado.GetInt(sql);
                tableRowMap.Add(table, count);
                ConsoleLog.Info("RichText", $"table name: {table},count: {count}");
            }

            Type sugarType = typeof(SqlSugarClient);
            List<Action> actions = new List<Action>();
            foreach (string table in tableRowMap.Keys)
            {
                // 动态获取实体类的类型
                Type entityType = DynamicHelper.ModelAssembly.GetType($"{namesp}.{table}");
                if (entityType == null)
                {
                    ConsoleLog.Error("RichText", $"未找到类型: {table}");
                    continue;
                }
                string tmpTable = table;
                actions.Add(() =>
                {
                    int totalRow = QueryAndInsert(sourceId, targetId, sugarType, tmpTable, entityType);
                    ConsoleLog.Success("RichText", $"共插入表: {table}, {totalRow} 行数据");
                });
            }
            Parallel.Invoke(new ParallelOptions()
            {
                CancellationToken = ct,
                MaxDegreeOfParallelism = 4
            }, actions.ToArray());
        }

        /// <summary>
        /// MySql 数据源向 Dm 数据源迁移
        /// </summary>
        /// <param name="sourceId"></param>
        /// <param name="targetId"></param>
        /// <param name="dbName"></param>
        /// <param name="namesp"></param>
        private void MySqlToOracleMigrate(string sourceId,string targetId,string dbName,string namesp)
        {

        }

        #endregion

        protected override List<ViewDefinition> GetViewDefinitions(string mode)
        {
            string sql = $"SELECT TABLE_SCHEMA as TABLE_NAME,TABLE_NAME as VIEW_NAME,VIEW_DEFINITION FROM information_schema.VIEWS where TABLE_SCHEMA = '{mode}';";
            return DB.Ado.SqlQuery<ViewDefinition>(sql);
        }

        #region 视图结构转换

        string initDirPath = Directory.GetCurrentDirectory();

        /// <summary>
        /// 根据表名 纠正 mysql 视图中的表名小写问题
        /// </summary>
        /// <param name="table"></param>
        public void CorrectMySqlView(string table)
        {
            string sql = $"select TABLE_NAME from information_schema.`TABLES` where TABLE_SCHEMA = '{table}' and TABLE_TYPE = 'BASE TABLE'";
            List<string> tableNames = DB.Ado.SqlQuery<string>(sql);
            string sql2 = $"select TABLE_NAME as VIEW_NAME,VIEW_DEFINITION from information_schema.VIEWS where TABLE_SCHEMA = '{table}'";
            List<ViewDefinition> views = DB.Ado.SqlQuery<ViewDefinition>(sql2);

            SaveFileDialog fileDialog = new SaveFileDialog();
            fileDialog.InitialDirectory = initDirPath;
            fileDialog.Filter = "sql文件|*.sql|文本文件|*.txt";
            if (fileDialog.ShowDialog() != DialogResult.OK)
                return;

            string fileName = fileDialog.FileName;
            initDirPath = Directory.GetParent(fileName).FullName;
            foreach (var view in views)
            {
                string viewSql = view.VIEW_DEFINITION.Replace($"`{table}`.", " ", StringComparison.OrdinalIgnoreCase);

                foreach (var tableName in tableNames)
                {
                    if (viewSql.Contains(tableName, StringComparison.OrdinalIgnoreCase))
                    {
                        viewSql = viewSql.Replace(tableName.ToLower(), tableName, StringComparison.OrdinalIgnoreCase);
                    }
                }

                string template = $"CREATE OR REPLACE VIEW `{table}`.`{view.VIEW_NAME}` AS {viewSql}\r\n\n";

                File.AppendAllText(fileName, template);
            }
        }

        #endregion
    }
}
